package me.thinkjet.sso.client.validation;

import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import me.thinkjet.sso.client.encoding.Encoder;
import me.thinkjet.sso.client.encoding.Md5Encoder;
import me.thinkjet.sso.client.util.CommonUtils;
import me.thinkjet.sso.client.util.HttpUtils;

public abstract class AbstractUrlBasedTicketValidator implements
		TicketValidator {

	private final String validateUrl;
	private final String clientId;
	private final String key;

	protected AbstractUrlBasedTicketValidator(final String validateUrl,
			final String clientId, final String key) {
		this.validateUrl = validateUrl;
		this.clientId = clientId;
		this.key = key;
		CommonUtils.assertNotNull(this.validateUrl,
				"validateUrl cannot be null.");
		CommonUtils.assertNotNull(this.clientId, "clientId cannot be null.");
		CommonUtils.assertNotNull(this.key, "clientId cannot be null.");
	}

	protected final String constructValidationUrl(final String ticket) {
		final Map<String, String> urlParameters = new HashMap<String, String>();
		Encoder encoder = new Md5Encoder();
		urlParameters.put("key", encoder.encode(ticket, key));
		urlParameters.put("client", clientId);
		urlParameters.put("ticket", ticket);

		final StringBuilder buffer = new StringBuilder(urlParameters.size()
				* 10 + this.validateUrl.length());

		int i = 0;

		buffer.append(this.validateUrl);
		for (Map.Entry<String, String> entry : urlParameters.entrySet()) {
			final String key = entry.getKey();
			final String value = entry.getValue();

			if (value != null) {
				buffer.append(i++ == 0 ? "?" : "&");
				buffer.append(key);
				buffer.append("=");
				buffer.append(value);
			}
		}

		return buffer.toString();

	}

	protected final String encodeUrl(final String url) {
		if (url == null) {
			return null;
		}

		try {
			return URLEncoder.encode(url, "UTF-8");
		} catch (final UnsupportedEncodingException e) {
			return url;
		}
	}

	protected abstract Assertion parseResponseFromServer(final String response)
			throws TicketValidationException;

	protected String retrieveResponseFromServer(URL validationUrl, String ticket) {
		return HttpUtils.getResponseFromServer(validationUrl, "UTF-8");
	}

	public Assertion validate(final String ticket)
			throws TicketValidationException {

		final String validationUrl = constructValidationUrl(ticket);
		try {
			final String serverResponse = retrieveResponseFromServer(new URL(
					validationUrl), ticket);

			if (serverResponse == null) {
				throw new TicketValidationException(
						"The CAS server returned no response.");
			}

			return parseResponseFromServer(serverResponse);
		} catch (final MalformedURLException e) {
			throw new TicketValidationException(e);
		}
	}

}
